package app.modules.security.business.service.function;

import app.modules.common.constant.CommonLockConstants;
import app.modules.security.business.service.SyncRbacCacheService;
import app.modules.security.constant.SecurityLockConstants;
import app.modules.security.dto.web.permission.WebPermissionDTO;
import app.modules.security.persistence.dao.FunctionPermissionRelationDAO;
import app.modules.security.persistence.dao.PermissionDAO;
import jasmine.framework.common.util.CheckUtil;
import jasmine.framework.common.util.CollectionUtil;
import jasmine.framework.lock.annotation.DistributedLock;
import jasmine.security.rbac.model.SecFunction;
import jasmine.security.rbac.model.SecFunctionPermissionRelation;
import jasmine.security.rbac.model.SecPermission;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author mh.z
 */
@Service
public class FunctionPermissionRelationService {
    private FunctionPermissionRelationDAO functionPermissionRelationDAO;
    private PermissionDAO permissionDAO;
    private SyncRbacCacheService syncRbacCacheService;

    public FunctionPermissionRelationService(FunctionPermissionRelationDAO functionPermissionRelationDAO,
                                             PermissionDAO permissionDAO, SyncRbacCacheService syncRbacCacheService) {
        this.functionPermissionRelationDAO = functionPermissionRelationDAO;
        this.permissionDAO = permissionDAO;
        this.syncRbacCacheService = syncRbacCacheService;
    }

    /**
     * 查询指定功能的所有已分配权限
     *
     * @param functionId
     * @return
     */
    public List<WebPermissionDTO> listAssignedPermissions(Long functionId) {
        List<WebPermissionDTO> recordList = functionPermissionRelationDAO.listAssignedPermissions(functionId);

        return recordList;
    }

    /**
     * 分配资源
     *
     * @param functionId
     * @param permissionIds
     */
    @DistributedLock(category = SecurityLockConstants.LOCK_CATEGORY_FUNCTION_ASSIGN_PERMISSIONS, key = CommonLockConstants.LOCK_KEY_ALL)
    @Transactional(rollbackFor = Exception.class)
    public void assignPermission(Long functionId, List<Long> permissionIds) {
        CheckUtil.notNull(functionId, "functionId null");
        CheckUtil.notNull(permissionIds, "permissionIds null");

        // 删除指定功能的所有权限分配关系
        functionPermissionRelationDAO.deleteByFunctionId(functionId);

        if (CollectionUtil.isNotEmpty(permissionIds)) {
            List<SecPermission> permissionList = permissionDAO.listByIds(permissionIds);
            permissionIds = CollectionUtil.mapToList(permissionList, SecPermission::getId);

            List<SecFunctionPermissionRelation> newRecordList = CollectionUtil.mapToList(permissionIds, (permissionId) -> {
                SecFunctionPermissionRelation newRecord = new SecFunctionPermissionRelation();
                newRecord.setFunctionId(functionId);
                newRecord.setPermissionId(permissionId);

                return newRecord;
            });

            if (CollectionUtil.isNotEmpty(newRecordList)) {
                // 保存功能和权限的分配关系
                functionPermissionRelationDAO.saveBatch(newRecordList);
            }
        }

        // 同步缓存
        syncRbacCacheService.syncFunctionsWithResourceIdCache(SecFunction.class, functionId);
    }

}
